package sw.service.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.easy.word.WordUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import sun.misc.BASE64Decoder;
import sw.dao.AssetDao;
import sw.dao.AssetTypeDao;
import sw.dao.ProjectDao;
import sw.dao.ResultDao;
import sw.dao.RiskLevelDao;
import sw.dao.ThreatDao;
import sw.dao.WeaknessDao;
import sw.entity.Asset;
import sw.entity.AssetType;
import sw.entity.Project;
import sw.entity.Result;
import sw.entity.RiskLevel;
import sw.entity.Threat;
import sw.entity.Weakness;
import sw.model.MAnalysis;
import sw.model.MResult;
import sw.model.MRiskLevel;
import sw.model.MThread;
import sw.model.MUserGroup;
import sw.model.MWeakness;
import sw.service.IGroupAuthManger;
import sw.service.IRiskCalculate;

@Service
public class RiskCalculateImpl implements IRiskCalculate{

	@Autowired
	private WeaknessDao weaknessDao;
	
	@Autowired
	private RiskLevelDao riskLevelDao;
	
	@Autowired
	private ResultDao resultDao;
	
	@Autowired
	private ProjectDao proDao;
	
	@Autowired
	private IGroupAuthManger groupAuthMangerImpl;
	
	@Autowired
	private AssetDao assetDao;
	
	@Autowired
	private ThreatDao  threadDao;
	
	@Autowired
	private AssetTypeDao assetTypeDao;
	
	@Value("${web.uploadImg-path}")
	protected String IMGPATH;
	
	@Override
	public Integer saveRiskLevel(MRiskLevel level) {
		Integer projectId = level.getId();
		Project pro = proDao.findOne(projectId);
		if(null == pro) return -1;
		RiskLevel riskLevel = new RiskLevel();
		riskLevel.setMinValue(level.getMinValue());
		riskLevel.setMaxValue(level.getMaxValue());
		riskLevelDao.save(riskLevel);
		return 0;
	}
	
	
	@Override
	public Map<String, List<MResult>> calculate(Integer projectId,Float acceptStandard) {
		Project pro = proDao.findOne(projectId);
		List<Weakness> weakList = weaknessDao.findByProjectId(projectId);
		if(null == weakList || weakList.size()==0) return null;
		 pro.setAcceptStandard(acceptStandard);
		 pro = proDao.save(pro);
		List<RiskLevel> levelList = riskLevelDao.findByProjectId(projectId);
		if(null == levelList || levelList.size()==0) return null;
		List<Result> results = new ArrayList<Result>();
		for(Weakness weakness :weakList){
			Float riskValue =	calRisk(weakness);//计算风险值
			RiskLevel level = null ;
			if(riskValue != null){
				level = setRiskLevel(riskValue,levelList);
			}
			if(null != level){
				Result result = new Result();
				result.setRiskValue(riskValue);
				result.setRiskLevel(level);
				result.setWeekness(weakness);
				results.add(result);
				if(acceptStandard>=riskValue){
					result.setIsAccept(1);
				}else{
					result.setIsAccept(0);
				}
			}
		}
		if(results.size() !=0){
			resultDao.save(results);
			 return null;
		}
		return null;
	}
	
	@Override
	public Map<String, List<MResult>> showResult(Integer projectId) {
		List<Result> results = resultDao.findBy(projectId);
		Map<String, List<MResult>> resultGroup = new HashMap<String, List<MResult>>();
		if(null == results || results.size() == 0) return resultGroup;
		for(Result re : results){
			
			String assetTypeName = re.getWeekness().getThread().getAsset().getAssetType().getName();
			List<MResult> temp;
			if(resultGroup.containsKey(assetTypeName)){
				temp = resultGroup.get(assetTypeName);
			}else{
				temp = new ArrayList<MResult>();
			}
			MResult model = new MResult(re);
			temp.add(model);
			resultGroup.put(assetTypeName, temp);
		}
	
		return resultGroup;
	}
	
	private Float calRisk(Weakness weakness){
		Float severity = weakness.getSeverity();//获得脆弱性
		Float frequency = weakness.getThread().getFrequency();
		Float importance = weakness.getThread().getAsset().getImportance();
		
		if(severity!=null && frequency!=null && importance != null){
			Float safePossibility = (float) Math.sqrt(frequency*severity);//计算安全事件发生可能性
			Float safeLoss = (float) Math.sqrt(importance * severity);//计算安全时间的损失
			Float risk = safePossibility * safeLoss;
			return (float) Math.floor(risk);
		}
		return null;
	}
	
	
	/**
	 * 设置风险等级
	 * @param riskValue
	 * @param riskList
	 * @return
	 */
	private RiskLevel setRiskLevel(Float riskValue,List<RiskLevel> riskList){
		for(RiskLevel level : riskList){
			if(riskValue>=level.getMinValue() && riskValue<=level.getMaxValue()){
				return level;
			}
		}
		return null;
	}

	@Override
	public String exportWord(Integer projectId, String path,String img1,String img2) throws Exception {
		
		
		
		WordUtils mdoc = new WordUtils(); 
		//mdoc.decodeBase64(img1, IMGPATH);
		
		Map<String, Object> dataMap = new HashMap<String, Object>(); 
		  Project project = proDao.findOne(projectId);
		  dataMap.put("project", project); 
		  dataMap.put("time", "2018年");//时间
		  dataMap.put("conclusion", null);//风险评估报告结论
		 
		  if(null != project.getGplot()){//取到对应拓扑图
			  String src = Paths.get(IMGPATH,project.getGplot()).toString();
			  String img = mdoc.getImageBase(src);
			  dataMap.put("image", img);//图片
		  }
		  //设置评估组织
		  List<MUserGroup> userGroupProjects = groupAuthMangerImpl.findAllGroups(projectId);
		  dataMap.put("projectUser", userGroupProjects);
		  
		  //资产识别
		  dataMap = setAssets(projectId, dataMap);
		  
		  //重要资产赋值
		  dataMap =setImpAssets(projectId, dataMap, project.getImpStandard());
		  
		  //威胁
		  dataMap = setThreats(projectId, dataMap,  project.getImpStandard());
		  
		  //脆弱性
		  dataMap = setWeakness(projectId, dataMap, project.getImpStandard());
		  
		  //设置返回结果
		  dataMap = setResult(projectId,dataMap);
		  
		  //根据等级统计风险个数
		  dataMap = analysisByLevelName(projectId, dataMap);
		  
		  //根据是否可接受统计项目
		  dataMap = analysisByAccept(projectId, dataMap);
		  
		  if(img1 != null){
			  img1 = img1.replaceAll(" ", "+");
			  String[] arr = img1.split("base64,");  
			  dataMap.put("image2", arr[1]);//图片
		  }
		  if(img2 != null){
			  img2 = img2.replaceAll(" ", "+");
			  String[] arr = img2.split("base64,");  
			  dataMap.put("image3", arr[1]);//图片
		  }
		  
//		  String src = Paths.get(IMGPATH,"img1.png").toString();
//		  String imgStr2 = mdoc.getImageBase(src);
//		  dataMap.put("image2", imgStr2);//图片
//			  
//		  String src3 = Paths.get(IMGPATH,"img2.png").toString();
//		  String imgStr3 = mdoc.getImageBase(src3);
//		  dataMap.put("image3", imgStr3);
	  
		  mdoc.createDoc(dataMap,path);
		return null;
	}
	
	
	/**
	 * 设置资产类型
	 * @param projectId
	 * @param dataMap
	 * @return
	 */
	private Map<String, Object> setAssets(Integer projectId, Map<String, Object> dataMap) {
		List<Asset> assets = assetDao.findByProjectId(projectId);
		if(null == assets) return null;
		Map<String, List<Asset>> assetGroup = new HashMap<String, List<Asset>>();
		 List<Asset> temp;
		for(Asset asset :assets ){
			AssetType type = asset.getAssetType();
			String excelName = type.getImportExcel();
			if(assetGroup.containsKey(excelName)){
				temp = assetGroup.get(excelName);
			}else{
				temp = new ArrayList<Asset>();
			}
			temp.add(asset);
			assetGroup.put(excelName, temp);
		}
		
		for(String key : assetGroup.keySet()){
			if(assetGroup.get(key).size() ==0){
				dataMap.put(key, null);
			}else{
				dataMap.put(key, assetGroup.get(key));
			}
			
		}
		
		return dataMap;
	}
	/**
	 * 设置重要资产
	 * @param projectId
	 * @param dataMap
	 * @param importance
	 * @return
	 */
	private Map<String, Object> setImpAssets(Integer projectId,Map<String, Object> dataMap, Float importance) {
		List<Asset> assets = assetDao.findImportantAsset(projectId, importance);
		if(null == assets) return null;
		Map<String, List<Asset>> assetGroup = new HashMap<String, List<Asset>>();
		 List<Asset> temp;
		for(Asset asset :assets ){
			AssetType type = asset.getAssetType();
			String excelName = "imp"+type.getImportExcel();
			if(assetGroup.containsKey(excelName)){
				temp = assetGroup.get(excelName);
			}else{
				temp = new ArrayList<Asset>();
			}
			temp.add(asset);
			assetGroup.put(excelName, temp);
		}
		
		for(String key : assetGroup.keySet()){
			if(assetGroup.get(key).size() ==0){
				dataMap.put(key, null);
			}else{
				dataMap.put(key, assetGroup.get(key));
			}
			
		}
		
		return dataMap;
	}
	
	/**
	 * 设置威胁
	 * @param projectId
	 * @param dataMap
	 * @param importance
	 * @return
	 */
	private Map<String, Object> setThreats(Integer projectId,Map<String, Object> dataMap, Float importance) {
		List<Asset> assets =assetDao.findImportantAsset(projectId, importance);
		if(null == assets) return null;
		Map<String, List<MThread>> threatGroup = new HashMap<String, List<MThread>>();
		 List<MThread> temp;
		for(Asset asset :assets ){
			AssetType type = asset.getAssetType();
			String excelName = "trt"+type.getImportExcel();
			if(threatGroup.containsKey(excelName)){
				temp = threatGroup.get(excelName);
			}else{
				temp = new ArrayList<MThread>();
			}
			List<Threat> threaList = threadDao.findByAssetId(asset.getId());
			for(Threat th : threaList){
				MThread model = new MThread(asset.getName(), asset.getDepart(), th.getThreatName());
				temp.add(model);
			}
			
			threatGroup.put(excelName, temp);
		}	
		
		for(String key : threatGroup.keySet()){
			if(threatGroup.get(key).size() ==0){
				dataMap.put(key, null);
			}else{
				dataMap.put(key, threatGroup.get(key));
			}
		}
		return dataMap;
	}
	
	/**
	 * 设置脆弱性
	 * @param projectId
	 * @param dataMap
	 * @param importance
	 * @return
	 */
	private Map<String, Object> setWeakness(Integer projectId,Map<String, Object> dataMap, Float importance) {
		List<Asset> assets = assetDao.findImportantAsset(projectId, importance);
		if(null == assets) return null;
		Map<String, List<MWeakness>> weakGroup = new HashMap<String, List<MWeakness>>();
		 List<MWeakness> temp;
		for(Asset asset :assets ){//针对每个资产
			AssetType type = asset.getAssetType();
			String typeName = "weak"+type.getImportExcel();
			int index =1;
			if(weakGroup.containsKey(typeName)){ 
				temp = weakGroup.get(typeName);
				index = temp.size()+1;
			}else{
				temp = new ArrayList<MWeakness>();
			}
			List<Weakness> weakList = weaknessDao.findByAssetId(asset.getId());
			for(Weakness weak : weakList){
				MWeakness model = new MWeakness(index,asset.getName(),weak.getName());
				temp.add(model);
				index++;
			}
			
			weakGroup.put(typeName,temp);
		}
		for(String key : weakGroup.keySet()){
			if(weakGroup.get(key).size() ==0){
				dataMap.put(key, null);
			}else{
				dataMap.put(key, weakGroup.get(key));
			}
		}
		return dataMap;
	}
	
	/**
	 * 设置风险评估结果
	 * @param projectId
	 * @param dataMap
	 * @return
	 */
	private Map<String, Object> setResult(Integer projectId, Map<String, Object> dataMap) {
		List<Result> results = resultDao.findBy(projectId);
		Map<String, List<MResult>> resultGroup = new HashMap<String, List<MResult>>();
		if(null == results || results.size() == 0) return null;
		for(Result re : results){
			int index =1;
			String assetTypeName = "res" + re.getWeekness().getThread().getAsset().getAssetType().getImportExcel();
			List<MResult> temp;
			if(resultGroup.containsKey(assetTypeName)){
				temp = resultGroup.get(assetTypeName);
				index = temp.size()+1;
			}else{
				temp = new ArrayList<MResult>();
			}
			MResult model = new MResult(index,re);
			temp.add(model);
			resultGroup.put(assetTypeName, temp);
			index++;
		}
		for(String key : resultGroup.keySet()){
			if(resultGroup.get(key).size() ==0){
				dataMap.put(key, null);
			}else{
				dataMap.put(key, resultGroup.get(key));
			}
		}
		return dataMap;
	}
	
	/**
	 * 根据等级统计风险个数
	 * @param projectId
	 * @param dataMap
	 * @return
	 */
	private Map<String, Object> analysisByLevelName(Integer projectId,Map<String, Object> dataMap){//
		List<Result> results = resultDao.findBy(projectId);
		Map<String, List<MResult>> resultGroup = new HashMap<String, List<MResult>>();
		if(null == results || results.size() == 0) return null;
		for(Result re : results){
			int index =1;
			String levelName =re.getRiskLevel().getName();
			List<MResult> temp;
			if(resultGroup.containsKey(levelName)){
				temp = resultGroup.get(levelName);
				index = temp.size()+1;
			}else{
				temp = new ArrayList<MResult>();
			}
			MResult model = new MResult(index,re);
			temp.add(model);
			resultGroup.put(levelName, temp);
			index++;
		}
		List<MAnalysis> analysisList = new ArrayList<MAnalysis>();
		for(String key : resultGroup.keySet()){
			List<MResult> resultList = resultGroup.get(key);
			analysisList.add(new MAnalysis(key,resultList.size()));
		}
		dataMap.put("levelGroup", analysisList);
		return dataMap;
	}
	/**
	 * 根据是否可接受统计项目
	 * @param projectId
	 * @param dataMap
	 * @return
	 */
	private Map<String, Object> analysisByAccept(Integer projectId,Map<String, Object> dataMap){
		List<Result> results = resultDao.findBy(projectId);
		Map<Integer, List<MResult>> resultGroup = new HashMap<Integer, List<MResult>>();
		if(null == results || results.size() == 0) return null;
		for(Result re : results){
			int index =1;
			Integer isAccept =re.getIsAccept();
			List<MResult> temp;
			if(resultGroup.containsKey(isAccept)){
				temp = resultGroup.get(isAccept);
				index = temp.size()+1;
			}else{
				temp = new ArrayList<MResult>();
			}
			MResult model = new MResult(index,re);
			temp.add(model);
			resultGroup.put(isAccept, temp);
			index++;
		}
		List<MAnalysis> analysisList = new ArrayList<MAnalysis>();
		for(Integer key : resultGroup.keySet()){
			String str;
			if(null != key && !key.equals(0)) {
				str="不可接受风险";
			}else{
				str="可接受风险";
			}
			List<MResult> resultList = resultGroup.get(key);
			analysisList.add(new MAnalysis(str,resultList.size()));
		}
		dataMap.put("acceptGroup", analysisList);
		return dataMap;
	}
}
